using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Win32;
using System.IO;
using System.Xml.Serialization;
using System.Threading;
using System.Windows.Threading;
using WozLib.Net;
using WozLib.UI.Ink;
using System.Windows.Input;
using WozLib.UI.Dialogs;
using WozLib.UI.Ink.SketchCommands;
using WozLib.UI.Ink.SketchObjects;
using WozLib.UI.Ink.SketchElements;
using System.ComponentModel;


namespace SketchWizardPlayer
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>

  public partial class Window1 : System.Windows.Window, INotifyPropertyChanged
  {
    private SketchCommandCollection _WozClientCommands = new SketchCommandCollection();

    private SketchCommandCollection _PendingWozClientCommands = new SketchCommandCollection();

    private SketchCommandReferences _ClientCommandReferences;

    private SketchObjectRegistry _WozObjectRegistry = new SketchObjectRegistry();

    public bool NoDelays
    {
      get { return _NoDelays; }
      set 
      { 
        _NoDelays = value;
        NotifyPropertyChanged("NoDelays");
      }
    } private bool _NoDelays = false;

    public bool IsPaused
    {
      get { return _IsPaused; }
      set 
      { 
        _IsPaused = value;
        NotifyPropertyChanged("IsPaused");
      }
    } private bool _IsPaused = false;

    public bool IsNotPaused
    {
      get { return !IsPaused; }
      set 
      { 
        IsPaused = !value;
        NotifyPropertyChanged("IsNotPaused");
      }
    }

    public Window1()
    {
      CommandBinding closeCommandBinding = new CommandBinding(ApplicationCommands.Close);
      closeCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(closeCommandBinding_CanExecute);
      closeCommandBinding.Executed += new ExecutedRoutedEventHandler(closeCommandBinding_Executed);
      CommandBindings.Add(closeCommandBinding);

      InitializeComponent();

      // Don't touch any interface components until load()"
      this.Loaded += new RoutedEventHandler(ClientWindow_Loaded);
      this.SizeChanged += new SizeChangedEventHandler(ClientWindow_SizeChanged);

      List<string> editingModes = new List<string>();
    }

    void closeCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      this.Close();
    }

    void closeCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
      e.CanExecute = true;
    }

    void ClientWindow_SizeChanged(object sender, SizeChangedEventArgs e)
    {
      // Let's ignore client resizing of the window

      //Size newSize = e.NewSize;
      //Size previousSize = e.PreviousSize;
      //_ClientInkCanvas.Width = newSize.Width;
      //_ClientInkCanvas.Height = newSize.Height;
      //CommandOccured(new WozWindowResizeCommand(newSize,previousSize));
    }

    void ClientWindow_Loaded(object sender, RoutedEventArgs e)
    {
      this.KeyDown += new KeyEventHandler(ClientWindow_KeyDown);

      _NoDelayCheck.Checked += new RoutedEventHandler(_NoDelayCheck_Checked);
      _NoDelayCheck.Unchecked += new RoutedEventHandler(_NoDelayCheck_Unchecked);
      _PlayRadio.Checked += new RoutedEventHandler(_PlayRadio_Checked);
      _PauseRadio.Checked += new RoutedEventHandler(_PauseRadio_Checked);

      // for now let's assume the client cannot resize
      this.ResizeMode = ResizeMode.NoResize;

      //_FullScreenRadio.Click += new RoutedEventHandler(_FullScreenRadio_Click);
      _FullScreenCheck.Unchecked += new RoutedEventHandler(_FullScreenCheck_Unchecked);
      _FullScreenCheck.Checked += new RoutedEventHandler(_FullScreenCheck_Checked);

      // Set references for executing ClientCommands
      _ClientCommandReferences = new SketchCommandReferences();
      _ClientCommandReferences.InkCanvas = _ClientInkCanvas;
      _ClientCommandReferences.InFrontInkCanvas = _InkOverlayCanvas;
      _ClientCommandReferences.ClientWindow = new WozLib.UI.Containers.WozSizeable(_ClientInkCanvas, this);
      _ClientCommandReferences.InkOverlayCanvas = _InkOverlayCanvas;
      _ClientCommandReferences.WozObjectRegistry = _WozObjectRegistry;

      _ClientInkCanvas.SketchObjectRegistry = _WozObjectRegistry;
      _ToolSelectToolbar.UserToolsEnabledCollection = new List<SketchPad.InkTools>(new SketchPad.InkTools[] 
        {  
          SketchPad.InkTools.Eraser,
          SketchPad.InkTools.Pencil
        });
      _ClientInkCanvas.UserToolsEnabledCollectionChanged += new SketchInkCanvas.UserToolsEnabledCollectionChangedHandler(_ClientInkCanvas_UserToolsEnabledCollectionChanged);
      _ClientInkCanvas.UserCurrentInkToolChanged += new SketchInkCanvas.UserCurrentInkToolChangedHandler(_ClientInkCanvas_UserCurrentInkToolChanged);
      _ToolSelectToolbar.SelectedToolChanged += new WozLib.UI.Controls.ToolSelectToolbar.SelectedToolChangedHandler(_ToolSelectToolbar_SelectedToolChanged);

      SketchButton.SketchButtonCreated += new SketchButton.SketchButtonCreatedDelegate(SketchButton_SketchButtonCreated);
    }

    void _PauseRadio_Checked(object sender, RoutedEventArgs e)
    {
      IsPaused = true;
    }

    void _PlayRadio_Checked(object sender, RoutedEventArgs e)
    {
      IsNotPaused = true;
      _timer_Tick(null, null);
    }

    void _NoDelayCheck_Unchecked(object sender, RoutedEventArgs e)
    {
    }

    void _NoDelayCheck_Checked(object sender, RoutedEventArgs e)
    {
      _timer_Tick(null, null);
    }

    void SketchButton_SketchButtonCreated(SketchButton sketchButton)
    {
      sketchButton.Button.Click += new RoutedEventHandler(Button_Click);
    }

    void Button_Click(object sender, RoutedEventArgs e)
    {
      // capture user clicks and send them across the wire
      //if (sender is Button && (sender as Button).Parent is SketchButton)
      //{
      //  UserButtonActionSketchCommand userButtonActionSketchCommand = new UserButtonActionSketchCommand(
      //    ((sender as Button).Parent as SketchButton).GetWozObject());

      //  CommandOccured(userButtonActionSketchCommand);
      //}
    }

    private bool _SettingCurrentTool = false;

    void _ToolSelectToolbar_SelectedToolChanged(SketchPad.InkTools tool)
    {
      if (!_SettingCurrentTool)
      {
        _SettingCurrentTool = true;
        _ClientInkCanvas.UserCurrentInkTool = tool;
        //_ClientInkCanvas_CommandOccured(new ModifyUserCurrentInkTool(tool));
        _SettingCurrentTool = false;
      }
    }

    void _ClientInkCanvas_UserCurrentInkToolChanged(SketchPad.InkTools newInkTool, SketchPad.InkTools previousInkTool)
    {
      if (!_SettingCurrentTool)
      {
        _SettingCurrentTool = true;
        _ToolSelectToolbar.SelectTool(newInkTool);
        _SettingCurrentTool = false;
      }
    }

    void _ClientInkCanvas_UserToolsEnabledCollectionChanged(List<SketchPad.InkTools> newInkToolCollection, List<SketchPad.InkTools> previousInkToolCollection)
    {
      _ToolSelectToolbar.UserToolsEnabledCollection = newInkToolCollection;
    }

    void Hide_Click(object sender, RoutedEventArgs e)
    {
      ToggleToolbar();
    }

    private void ToggleToolbar()
    {
      if (_ToolBarTray.Visibility == Visibility.Visible)
      {
        _ToolBarTray.Visibility = Visibility.Collapsed;
      }
      else
      {
        _ToolBarTray.Visibility = Visibility.Visible;
      }
    }

    void ClientWindow_KeyDown(object sender, KeyEventArgs e)
    {
      switch (e.Key)
      {
        case Key.F1:
          ToggleToolbar();
          break;
        case Key.F10:
          goto case Key.F1;
        case Key.F11:
          goto case Key.F1;
        case Key.F12:
          goto case Key.F1;
        case Key.F13:
          goto case Key.F1;
        case Key.F14:
          goto case Key.F1;
        case Key.F15:
          goto case Key.F1;
        case Key.F16:
          goto case Key.F1;
        case Key.F17:
          goto case Key.F1;
        case Key.F18:
          goto case Key.F1;
        case Key.F19:
          goto case Key.F1;
        case Key.F2:
          goto case Key.F1;
        case Key.F20:
          goto case Key.F1;
        case Key.F21:
          goto case Key.F1;
        case Key.F22:
          goto case Key.F1;
        case Key.F23:
          goto case Key.F1;
        case Key.F24:
          goto case Key.F1;
        case Key.F3:
          goto case Key.F1;
        case Key.F4:
          goto case Key.F1;
        case Key.F5:
          goto case Key.F1;
        case Key.F6:
          goto case Key.F1;
        case Key.F7:
          goto case Key.F1;
        case Key.F8:
          goto case Key.F1;
        case Key.F9:
          goto case Key.F1;
        default:
          break;
      }
    }

    void _FullScreenCheck_Unchecked(object sender, RoutedEventArgs e)
    {
      //this.BorderThickness = new Thickness(2.0);
      this.WindowStyle = WindowStyle.SingleBorderWindow;
      this.WindowState = WindowState.Normal;
      this.SizeToContent = SizeToContent.WidthAndHeight;
      //this.ResizeMode = ResizeMode.NoResize;
      double scaleX = 1.0;
      double scaleY = 1.0;
      //_ClientInkCanvas.LayoutTransform = new ScaleTransform(scaleX, scaleY);
      _InkOverlayCanvas.LayoutTransform = new ScaleTransform(scaleX, scaleY);
    }

    void _FullScreenCheck_Checked(object sender, RoutedEventArgs e)
    {
      //this.BorderThickness = new Thickness(0.0);
      double oldWidth = _ClientInkCanvas.Width;
      double oldHeight = _ClientInkCanvas.Height;
      this.SizeToContent = SizeToContent.Manual;
      this.WindowStyle = WindowStyle.None;
      this.WindowState = WindowState.Maximized;
      //this.ResizeMode = ResizeMode.NoResize;
      double scaleX = this.RenderSize.Width / oldWidth;
      double scaleY = this.RenderSize.Height / oldHeight;
      
      //_ClientInkCanvas.LayoutTransform = new ScaleTransform(scaleX, scaleY);
      _InkOverlayCanvas.LayoutTransform = new ScaleTransform(scaleX, scaleY);
    }

    //void pizzaGrammar_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
    //{
    //  SpeechSynthesizer _speechSynthesizer = new SpeechSynthesizer();
    //  _speechSynthesizer.Speak(e.Result.Text);
    //}

    void _WozClient_WozClientCommandsReceived(SketchCommandCollection wozClientCommands)
    {
      wozClientCommands.SetCommandReferences(_ClientCommandReferences);
      _WozClientCommands.AddWozClientCommand(wozClientCommands.WozClientCommandList);
      RunCommands(wozClientCommands);
    }

    public void RunCommands(SketchCommandCollection wozClientCommands)
    {
      this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new RunCommandsDelgate(RunCommandsInternal), wozClientCommands);
    }

    private delegate void RunCommandsDelgate(SketchCommandCollection wozClientCommands);

    bool _RunningServerChanges = false;
    private void RunCommandsInternal(SketchCommandCollection wozClientCommands)
    {
      _RunningServerChanges = true;
      wozClientCommands.RedoAll();
      _RunningServerChanges = false;
    }




    /// <summary>
    /// if the calling textbox is not focused, this method focuses the textbox
    /// and selects all the text. One would use this method as the PreviewMouseDown
    /// for textboxes where they want the user to just be able to type a new
    /// value after the textbox is clicked once.
    /// 
    /// We cannot use GotFocus because the click handler will unselect the text and
    /// place the cursor at the click point
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void _TextBox_SelectAll_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
      // if it was a textbox that was clicked and its not selected
      if (sender is TextBox && !(sender as TextBox).IsFocused)
      {
        // select all the text
        (sender as TextBox).SelectAll();

        // give the textbox input focus
        (sender as TextBox).Focus();

        // set handled to true to prevent the regular textbox click code from running
        e.Handled = true;
      }
    }

    /// <summary>
    /// this method focuses the textbox and selects all the text. 
    /// One would use this method as the GotFocus
    /// for textboxes where they want the user to just be able to type a new
    /// value after the textbox is tabbed into.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void _TextBox_SelectAll_GotFocus(object sender, RoutedEventArgs e)
    {
      if (sender is TextBox)
      {
        // select all the text
        (sender as TextBox).SelectAll();
      }
    }

    void Load_Click(object sender, RoutedEventArgs e)
    {
      OpenFileDialog openFileDialog = new OpenFileDialog();
      openFileDialog.Title = "Where do you want to load the Canvas from?";
      openFileDialog.Filter = "XML|*.xml";

      if (openFileDialog.ShowDialog() == true)
      {
        // Set references for executing ClientCommands
        _ClientCommandReferences = new SketchCommandReferences();
        _ClientCommandReferences.InkCanvas = _ClientInkCanvas;
        _ClientCommandReferences.InFrontInkCanvas = _InkOverlayCanvas;
        _ClientCommandReferences.ClientWindow = new WozLib.UI.Containers.WozSizeable(_ClientInkCanvas, this);
        _ClientCommandReferences.InkOverlayCanvas = _InkOverlayCanvas;
        _ClientCommandReferences.WozObjectRegistry = _WozObjectRegistry;

        _ClientInkCanvas.SketchObjectRegistry = _WozObjectRegistry;

        // Insert code to set properties and fields of the object.
        XmlSerializer mySerializer = new XmlSerializer(typeof(SketchCommandCollection));

        StreamReader sr = new StreamReader(openFileDialog.FileName);

        SketchCommandCollection unserialized = (SketchCommandCollection)mySerializer.Deserialize(sr);

        unserialized.SetCommandReferences(_ClientCommandReferences);

        sr.Close();

        //unserialized.RedoAll();
        if (unserialized.WozClientCommandList.Count > 0)
        {
          _playCommandList = unserialized.WozClientCommandList;
          _playIndex = 0;
          _timer = new DispatcherTimer();
          _timer.Tick += new EventHandler(_timer_Tick);
          _timer.Interval = new TimeSpan(0);
          _timer.Start();
        }
      }
    }

    void _timer_Tick(object sender, EventArgs e)
    {
      if (!IsPaused && _playIndex < _playCommandList.Count)
      {
        _playCommandList[_playIndex].Redo();

        _playIndex++;

        if (_playIndex < _playCommandList.Count)
        {
          TimeSpan delta = _playCommandList[_playIndex].Timestamp.Subtract(_playCommandList[_playIndex - 1].Timestamp);
          //if (delta.TotalSeconds < 0){
          // enabling super fast playback
          if (NoDelays || delta.TotalSeconds < 0)
          {
            delta = new TimeSpan(0);
          }
          _timer.Interval = delta; 
          _timer.Start();
        }
      } 
    }

    private DispatcherTimer _timer;
    private List<SketchCommand> _playCommandList;
    private int _playIndex;

    void Ink_Click(object sender, RoutedEventArgs e)
    {
      _ClientInkCanvas.EditingMode = InkCanvasEditingMode.Ink;
    }

    void Gesture_Click(object sender, RoutedEventArgs e)
    {
      _ClientInkCanvas.EditingMode = InkCanvasEditingMode.GestureOnly;
    }

    void InkGesture_Click(object sender, RoutedEventArgs e)
    {
      _ClientInkCanvas.EditingMode = InkCanvasEditingMode.InkAndGesture;
    }

    void Erase_Click(object sender, RoutedEventArgs e)
    {
      _ClientInkCanvas.EditingMode = InkCanvasEditingMode.EraseByStroke;
    }

    void Select_Click(object sender, RoutedEventArgs e)
    {
      _ClientInkCanvas.EditingMode = InkCanvasEditingMode.Select;
    }

    void None_Click(object sender, RoutedEventArgs e)
    {
      _ClientInkCanvas.EditingMode = InkCanvasEditingMode.None;
    }


    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propertyName)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }


    #endregion
  }
}